<template>
  <div ref="imgBox" style="display: flex; align-items: center; justify-content: center; width: 100vw; height: 80vh; flex-direction: column;">
    <img :src="imgSrc" alt="stream" decoding="async" style="max-width: 100%; max-height: 100%; background: #000; cursor: crosshair;"
      @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove" @wheel="onWheel"
      @contextmenu.prevent draggable="false" />
    <div v-if="!connected" style="color: #fff; text-align: center; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);">正在连接...</div>
    <div style="margin-top: 8px; color: #ffd700; font-size: 1.1rem;">
      目标帧率: {{ displayFps }} FPS　实际帧率: {{ actualFps }} FPS　当前画质: {{ displayQuality }}
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';

const imgSrc = ref('');
const connected = ref(false);
let ws = null;
const imgBox = ref(null);
const props = defineProps({ backendIp: { type: String, default: 'localhost' }, fps: { type: Number, default: 24 }, quality: { type: Number, default: 0.7 } });

// 自适应参数
const adaptiveFps = ref(props.fps);
const adaptiveQuality = ref(props.quality);
const MAX_FPS = 60;
adaptiveFps.value = MAX_FPS;
// 新增：用于显示的响应式数值
const displayFps = computed(() => Math.round(adaptiveFps.value));
const displayQuality = computed(() => adaptiveQuality.value.toFixed(2));
// 新增：实际帧率统计
const actualFps = ref(0);
let frameCount = 0;
let fpsTimer = null;
let lastFrameTime = Date.now();
let delayList = [];
let autoAdjustTimer = null;

// 假设后端画面分辨率（可根据实际情况动态获取）
const remoteWidth = 1920;
const remoteHeight = 1080;

function sendMouseEvent(action, e) {
  if (!ws || ws.readyState !== 1) return;
  // 获取 img 在页面上的实际大小和位置
  const img = e.target;
  const rect = img.getBoundingClientRect();
  // 计算鼠标在图片上的相对坐标
  const x = Math.round((e.clientX - rect.left) * remoteWidth / rect.width);
  const y = Math.round((e.clientY - rect.top) * remoteHeight / rect.height);
  let button = 0;
  if (e.button === 0) button = 1; // 左键
  if (e.button === 2) button = 2; // 右键
  if (e.button === 1) button = 3; // 中键
  let amount = 0;
  if (action === 'wheel') amount = e.deltaY > 0 ? 1 : -1;
  ws.send(JSON.stringify({ type: 'mouse', action, x, y, button, amount }));
}

function onMouseDown(e) { sendMouseEvent('press', e); }
function onMouseUp(e) { sendMouseEvent('release', e); }
function onMouseMove(e) { sendMouseEvent('move', e); }
function onWheel(e) { sendMouseEvent('wheel', e); }

let lastUrl = '';
let pendingUrl = '';
function connect() {
  if (ws) ws.close();
  ws = new window.WebSocket(`ws://${props.backendIp}:8080/ws/screen`);
  ws.binaryType = 'arraybuffer';
  ws.onopen = () => { connected.value = true; };
  ws.onclose = () => { connected.value = false; setTimeout(connect, 2000); };
  ws.onerror = () => { connected.value = false; };
  ws.onmessage = (event) => {
    if (event.data instanceof ArrayBuffer) {
      if (pendingUrl) URL.revokeObjectURL(pendingUrl);
      const blob = new Blob([event.data], { type: 'image/jpeg' });
      pendingUrl = URL.createObjectURL(blob);

      // 预加载图片，加载完成后再切换显示，防止闪烁
      const preloadImg = new window.Image();
      preloadImg.onload = () => {
        if (lastUrl) URL.revokeObjectURL(lastUrl);
        lastUrl = pendingUrl;
        imgSrc.value = pendingUrl;
      };
      preloadImg.src = pendingUrl;

      // 帧延迟监测
      const now = Date.now();
      const delay = now - lastFrameTime;
      lastFrameTime = now;
      delayList.push(delay);
      if (delayList.length > 30) delayList.shift();
      checkNetworkAndAdjust();
      // 统计实际帧率
      frameCount++;
    }
  };
}

function reconnect() {
  connect();
}

function sendConfig() {
  if (ws && ws.readyState === 1) {
    ws.send(JSON.stringify({ type: 'config', fps: adaptiveFps.value, quality: adaptiveQuality.value }));
  }
}

function checkNetworkAndAdjust() {
  if (delayList.length < 10) return; // 数据不足不调整
  const avgDelay = delayList.reduce((a, b) => a + b, 0) / delayList.length;
  const MAX_FPS = 60;
  let changed = false;

  if (avgDelay > 120) {
    // 网络极差，强制降帧
    if (adaptiveFps.value > 24) { adaptiveFps.value = 24; changed = true; }
    if (adaptiveQuality.value > 0.4) { adaptiveQuality.value -= 0.05; changed = true; }
  } else if (avgDelay > 80) {
    // 网络一般，适当降帧
    if (adaptiveFps.value > 30) { adaptiveFps.value = 30; changed = true; }
    if (adaptiveQuality.value > 0.5) { adaptiveQuality.value -= 0.03; changed = true; }
  } else if (avgDelay < 60) {
    // 网络好，直接回升到60帧
    if (adaptiveFps.value !== MAX_FPS) { adaptiveFps.value = MAX_FPS; changed = true; }
    if (adaptiveQuality.value < props.quality) { adaptiveQuality.value += 0.02; changed = true; }
  }
  if (changed) sendConfig();
}

watch([() => props.fps, () => props.quality], ([newFps, newQuality]) => {
  adaptiveFps.value = newFps;
  adaptiveQuality.value = newQuality;
  sendConfig();
});

onMounted(() => {
  connect();
  fpsTimer = setInterval(() => {
    actualFps.value = frameCount;
    frameCount = 0;
  }, 1000);
});
onUnmounted(() => {
  if (ws) ws.close();
  if (fpsTimer) clearInterval(fpsTimer);
});

defineExpose({ reconnect });
</script> 